import org.junit.Test;
import static org.junit.Assert.*;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.util.List;

public class AutocompleteTest {

    @Test
    public void testAddWord() {
        Autocomplete ac = new Autocomplete();

        // add some words
        ac.addWord("apple", 100);
        ac.addWord("app", 50);
        ac.addWord("banana", 70);
        ac.addWord("band", 30);
        ac.addWord("pika~chu", 9999);

        // check prefix counts
        assertEquals(2, ac.countPrefixes("app"));
        assertEquals(2, ac.countPrefixes("ban"));
        assertEquals(0, ac.countPrefixes("pika~"));
        assertEquals(4, ac.countPrefixes(""));

        // check subtrie lookup
        assertNotNull(ac.getSubTrie("app"));
        assertNull(ac.getSubTrie("zzz"));

        // check suggestions
        List<ITerm> suggestions = ac.getSuggestions("app");
        assertEquals(2, suggestions.size());

        // check term content
        ITerm first = suggestions.get(0);
        ITerm second = suggestions.get(1);

        assertTrue(
                (first.getTerm().equals("apple") && second.getTerm().equals("app"))
                        || (first.getTerm().equals("app") && second.getTerm().equals("apple"))
        );
    }

    @Test
    public void testBuildTrie() throws Exception {
        // create temp file with test data
        File tempFile = File.createTempFile("testWords", ".txt");
        tempFile.deleteOnExit();

        try (BufferedWriter bw = new BufferedWriter(new FileWriter(tempFile))) {
            // write test words
            bw.write("100\tapple\n");
            bw.write("50\tapp\n");
            bw.write("70\tbanana\n");
            bw.write("30\tband\n");
            bw.write("9999\tpika~chu\n");
        }

        // build trie from file
        Autocomplete ac = new Autocomplete();
        Node root = ac.buildTrie(tempFile.getAbsolutePath(), 10);
        assertNotNull(root);

        // verify word insertion
        assertEquals(2, ac.countPrefixes("app"));
        assertEquals(2, ac.countPrefixes("ban"));
        assertEquals(0, ac.countPrefixes("pika"));

        // check suggestions
        List<ITerm> suggestions = ac.getSuggestions("app");
        assertEquals(2, suggestions.size());
    }

    @Test
    public void testEdgeCases() {
        Autocomplete ac = new Autocomplete();
        ac.addWord("hello", 100);

        // test empty prefix
        assertEquals(1, ac.getSuggestions("").size());
        assertEquals(1, ac.countPrefixes(""));

        // test null prefix
        assertNull(ac.getSubTrie(null));
        assertEquals(0, ac.getSuggestions(null).size());
        assertEquals(0, ac.countPrefixes(null));
    }

    @Test
    public void testInvalidCharacter() {
        Autocomplete ac = new Autocomplete();

        // add words with invalid chars
        ac.addWord("test1", 50);
        ac.addWord("test$", 50);
        ac.addWord("hello", 100);

        // verify only valid word inserted
        assertEquals(1, ac.countPrefixes(""));
        assertNotNull(ac.getSubTrie("hello"));
        assertNull(ac.getSubTrie("test1"));
        assertNull(ac.getSubTrie("test$"));
    }
}
